<!DOCTYPE html>
<html lang="zh-cmn-Hans">

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no" />
  <title>无 form 表单验证</title>
  <link rel="stylesheet" href="bootstrap.css" />
  <script src="../lib/Validator.js"></script>
  <style>

    .jumbotron {
      background: #61b2a7 url(bg.png) 0 50%;
      border-bottom: 1px solid rgba(34, 34, 34, 0.2);
      box-shadow: inset 0 10px 10px #61b2a7;
    }

    .jumbotron .title, .jumbotron a {
      color: white;
      text-shadow: 1px 1px 2px rgba(34, 34, 34, 0.5);
    }

    .valid-error {
      border-color: #a94442;
      color: #a94442;
      -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
      box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    }

    .valid-error:focus {
      border-color: #843534;
      -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
      box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
    }

    .valid-error-message {
      display: block;
      margin: 5px 0;
      font-style: normal;
      color: #a94442;
    }

    .valid-success {
      border-color: #3c763d;
      -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
      box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    }

    .valid-success:focus {
      border-color: #2b542c;
      -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
      box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
    }

  </style>
</head>

<body>


<div class="container">

  <h3>无 form 表单验证</h3>

  <div class="form-group">
    <label for="email">邮箱：</label>
    <input class="form-control" id="email" name="email" type="email" placeholder="请输入邮箱" />
  </div>

  <div class="form-group">
    <button class="btn btn-default" id="setErrorEmail" type="button">设置错误邮箱</button>
    <button class="btn btn-default" id="setRightEmail" type="button">设置正确邮箱</button>
    <button class="btn btn-info" id="validEmail" type="button">验证邮箱</button>
  </div>

  <div class="form-group">
    <label for="phone">手机：</label>
    <input class="form-control" id="phone" name="phone" type="text" placeholder="请输入手机号" />
  </div>

  <div class="form-group">
    <label for="birthday">生日：</label>
    <input class="form-control" id="birthday" name="birthday" type="text" placeholder="请填写生日">
  </div>

  <div class="form-group">
    <label>性别：</label>
    <div class="radio">
      <label>
        <input id="male" type="radio" name="sex" value="0" /> 男
      </label>
      <label>
        <input id="female" type="radio" name="sex" value="1" /> 女
      </label>
    </div>
  </div>

  <div class="form-group">
    <label for="city">城市：</label>
    <select class="form-control" id="city" name="city">
      <option value="">请选择</option>
      <option value="0">北京</option>
      <option value="1">上海</option>
      <option value="2">重庆</option>
      <option value="3">成都</option>
    </select>
  </div>

  <div class="form-group">
    <label>爱好：</label>
    <div class="checkbox">
      <label>
        <input id="badminton" name="hobby" type="checkbox" value="1" /> 羽毛球
      </label>
      <label>
        <input id="swim" name="hobby" type="checkbox" value="2" /> 游泳
      </label>
      <label>
        <input id="run" name="hobby" type="checkbox" value="3" /> 跑步
      </label>
    </div>
  </div>

  <div class="form-group">
    <label for="remarks">简介：</label>
    <textarea class="form-control" id="remarks" name="remarks" rows="3" placeholder="一句话描述自己"></textarea>
  </div>

  <input class="btn btn-primary" id="submit" type="button" value="提交" />

  <h3>序列化错误类</h3>

  <pre id="validate_result"></pre>

</div>

<script>
  var validator = new Validator({
    fields: {
      email: {
        rules: 'required | isEmail | maxLength(32)',
        messages: "不能为空 | 请输入合法邮箱 | 不能超过 {{param}} 个字符"
      },
      phone: {
        rules: 'is_phone',
        messages: "手机号： {{value}} 不合法"
      },
      birthday: {
        rules: 'required | isDate',
        messages: "不能为空 | 请输入合法日期"
      },
      sex: {
        rules: 'required',
        messages: "不能为空"
      },
      city: {
        rules: 'required',
        messages: "不能为空"
      },
      hobby: {
        rules: 'required | selectLimit(2)',
        messages: "不能为空 | 至少选择两项"
      },
      remarks: {
        rules: 'minLength(10) | maxLength(60)',
        messages: "不能少于 {{param}} 个字符 | 不能超过 {{param}} 个字符"
      }
    },
    // 参数：errorEl 错误信息节点，fieldEl 出现错误的表单节点
    errorPlacement: function (errorEl, fieldEl) {
      // 非 label 、radio 元素
      if (!isRadioOrCheckbox(fieldEl)) {
        fieldEl.parentNode.appendChild(errorEl);
      } else {
        fieldEl.parentNode.parentNode.parentNode.appendChild(errorEl);
      }
    },
    callback: function (errors, event) {

      var submitButton = document.getElementById('submit');
      removeClass(submitButton, 'btn-primary');
      // 如果错误为空
      if (!errors) {
        // 演示阻止表单提交
        validator.preventSubmit();
        // 设置成功按钮样式
        removeClass(submitButton, 'btn-danger');
        addClass(submitButton, 'btn-success');
        submitButton.value = '验证成功';
      } else {
        // 设置错误按钮样式
        removeClass(submitButton, 'btn-success');
        addClass(submitButton, 'btn-danger');
        submitButton.value = '验证失败';

      }
      // 结果显示
      document.getElementById('validate_result').innerHTML = JSON.stringify(errors);

    }
  });

  // checkbox 至少选择两项
  // 扩展内部验证方法 field: 验证域， param: 参数 如 selectLimit(2)
  validator.addMethod('selectLimit', function (field, param) {
    // checkbox 至少选择两项
    var checkedNum = 0;
    for (var i = 0, elLength = field.el.length; i < elLength; i++) {
      if (field.el[i].checked) {
        checkedNum += 1;
      }
    }
    return checkedNum >= param;
  });

  // 绑定表单改变事件
  validator.onInputEvent('email', 'all').onInputEvent('phone', 'change');

  // 点击验证
  document.getElementById('submit').onclick = function () {
    validator.validate();
  }

  // 设置邮箱值
  var emailEL = document.getElementById('email');

  var setErrorEmail = document.getElementById('setErrorEmail');
  addEvent(setErrorEmail, 'click', function () {
    emailEL.value = 'anonymous#qq.com';
  });

  var setRightEmail = document.getElementById('setRightEmail');
  addEvent(setRightEmail, 'click', function () {
    emailEL.value = 'anonymous@qq.com';
  });

  // 验证邮箱值
  var validEmailButton = document.getElementById('validEmail');
  addEvent(validEmailButton, 'click', function () {
    // 通过 name 验证单个表单域
    validator.validateByName('email');
  });

  // Demo 中未使用 jQuery 类库，作为演示添加方法

  /**
   * 判断节点是否为 radio 或者 checkbox
   * @param {Element} 传入节点
   * @return {Boolean}
   */
  function isRadioOrCheckbox(el) {
    return el.type === 'radio' || el.type === 'checkbox';
  }

  /**
   * 判断是否包含 class
   */
  function hasClass(el, cls) {
    return el.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
  }

  /**
   * 添加 class
   */
  function addClass(el, cls) {
    if (!hasClass(el, cls)) {
      el.classList ? el.classList.add(cls) : el.className += ' ' + cls;
    }
  }

  /**
   * 移除 class
   */
  function removeClass(el, cls) {
    if (hasClass(el, cls)) {
      var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
      el.classList ? el.classList.remove(cls) : el.className = el.className.replace(reg, ' ');
    }
  }

  /**
   * 添加事件
   */
  function addEvent(el, type, fn) {
    if (typeof el.addEventListener != 'undefined') {
      el.addEventListener(type, fn, false);
    } else if (typeof el.attachEvent != 'undefined') {
      el.attachEvent('on' + type, fn);
    } else {
      el['on' + type] = fn;
    }
    ;
  }

</script>
</body>

</html>